package com.youth.commonutils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/*
 * JWT的工具类
 * JWT主要用于按照一定的规则生成字符串，这个字符串里面包含用户信息，因为其他模块要共用jwt，所以放在common模块里面
 * 需要注意的是，使用JWT需要引入JWT的依赖
 * */
public class JwtUtils {

    /*设置token的过期时间*/
    public static final long EXPIRE = 1000 * 60 * 60 * 24;
    /*秘钥，自己设定的，在公司里面有专门的秘钥*/
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";


    /*生成token字符串的方法，这个字符串里面有用户信息*/
    /*
     * 在方法里面这里是传递了两个参数，一个是用户id，一格用户名字，当然这里也可以传递多个值，三个四个五个参数都一样
     * */
    public static String getJwtToken(String id, String nickname) {

        /*生成jwt字符串*/
        String JwtToken = Jwts.builder()
                /*设置jwt的头信息，固定的，不需要改*/
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                /*setSubject是分类，设置过期时间*/
                .setSubject("guli-user")
                .setIssuedAt(new Date())       /*得到当前时间，再加上过期时间，如果超过这个值就表示过期了*/
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                /*设置token的主题部分,也就是用户信息*/
                .claim("id", id)
                .claim("nickname", nickname)
                /*设置token的签名hash*/
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }


    /**
     * 判断token是否存在与有效，也就是判断这个token是否是按照一定规则生成的，如果是就返回true，如果不是就返回false
     *
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
        if (StringUtils.isEmpty(jwtToken)) return false;
        try {
            /*根据秘钥来判定token是否是一个有效的token*/
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    /**
     * 判断token是否存在与有效 ,这个也是判断token是否有效，和刚才的方法一样，只是传递的参数不一样，
     * 下面传递的参数是request，HttpServletRequest是javaweb里面的，
     * 为了后面操作方便，我们需要把token值放在一个heade里面，也就是通过request在header里面把字符串得到，
     * 然后再做个验证，看它是不是有效的token
     * @param request
     * @return
     */
/*    public static boolean checkToken(HttpServletRequest request) {
        try {
            *//*通过request在header里面得到token,判断token是否有效*//*
            String jwtToken = request.getHeader("token");
            if(StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }*/


    /**
     * 根据token获取会员id
     *
     * @param request 这个方法也是传递的request作为参数，就是根据token字符串，获取到token字符串里面的数据
     *                比如现在我们拿到一个字符串，我们需要把这个字符串里面的用户数据取出来，
     * @return
     */
    /*从token里面获取用户信息*/
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
//        System.out.println("jwtToken:"+jwtToken);
        if (StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String) claims.get("id");/*这里相当于是根据id这个key获取到对应的value，因为原来存储进去也是这么存进去的*/
    }

    /*根据token直接获取当前登录用户的id和nickname并封装入UserDto*/
    public static UserDto getUserDtoByToken(String token){
        if(StringUtils.isEmpty(token)) return null;
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        return new UserDto((String) claims.get("id"), (String) claims.get("nickname"),null);
    }


}
